#include<bits/stdc++.h> 
using namespace std;
//	PAT考试是在不同的地方进行仿真考试的，最终的排名需要将各个地方的子排名列表合并起来
//1.每个输入具有一个测试用例，对于每一个测试用例，第一行包括一个正整数N≤100，表示N个考点
//2.然后N个块，每个块由一个正整数K≤300表示该考点考生数量，紧接着K行成绩情况。每一行成绩
//	情况包括13个数码组成的准考证号和一个考试成绩，用空格隔开。
//3.对于每一个测试用例，首先输出考生总数，然后按照：准考证号 最终排名 考场号 考场排名 的
//	格式输出。考场编号从1~N，这些输出必须按照最终排名的非递减排序。同成绩的人一定拥有同
//	排名，按照准考证号排序。
//4.
struct Testee{	//考生类，存储ID，成绩，考场号，考场排名。同时重载<运算符，使set可以直接在插入后进行排名 
	string ID;
	int score;
	int location_number;
	int local_rank;
	bool operator <(const Testee & b) const{
		if(score > b.score) return score>b.score;
		else if(score == b.score) return ID < b.ID;
		else return false;
	}
};   
bool cmp(Testee a, Testee b){	//用于考场内的排序 
	if(a.score > b.score) return a.score > b.score;
	else if(a.score == b.score) return a.ID < b.ID;
	else return false;
}
int main(){
	int N;
	cin>>N;	//N个考场 
	set<Testee> Tests;	//用于存储所有的考生 
	for(int i =1;i<=N;i++){
		int K;
		cin>>K;	// i考场有K个考生 
		Testee locations[K]; //存储该考场的学生信息 
		for(int j=0;j<K;j++){
			Testee testee;
			cin>>testee.ID>>testee.score; //读入成绩、ID 
			testee.location_number = i;	//考场号就是i 
			locations[j] = testee;
		}
		sort(locations,locations+K,cmp);	//对考场内的学生按照cmp函数进行排序 
		locations[0].local_rank = 1;	//第一名 
		Tests.insert(locations[0]);	//插入set中 
		for(int j=1;j<K;j++){
			if(locations[j].score == locations[j-1].score) locations[j].local_rank = locations[j-1].local_rank;	//同分延用排名 
			else locations[j].local_rank = j+1; //不同分则为位置 
			Tests.insert(locations[j]);	//插入set中 
		}
	}
	cout<<Tests.size()<<endl;	//全部学生的集合有多大就有多少人。且在处理完考场内部排名后，由于注入到set里，所以set内已经对全部学生排序好了 
	set<Testee>::iterator it;	//遍历 
	int rank = 1;	//初始排名 
	int max_ = Tests.begin()->score;	//第一名的成绩 
	int pos = 1;	//初始位置 
	for(it=Tests.begin();it!=Tests.end();it++){
		if(it->score<max_){
			max_ = it->score;
			rank = pos;
		}
		pos++;
		cout<<it->ID<<" "<<rank<<" "<<it->location_number<<" "<<it->local_rank<<endl;
	}
	return 0;
}